package com.xk.sport.backend.service;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.xk.sport.backend.common.entity.TaskQuery;
import com.xk.sport.backend.dao.model.*;
import com.xk.sport.backend.dao.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.xk.sport.backend.common.constant.TaskStatus.*;

@Service
public class TaskService {
    @Autowired
    private TaskDao taskDao;
    @Autowired
    private LessonDao lessonDao;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private TeacherLessonDao teacherLessonDao;
    @Autowired
    private CommunityDao communityDao;

    public Page<Task> findAllByQuery(TaskQuery query) {
        Pageable pageable = new PageRequest(query.getPageNum(), query.getSize(), 0 == query.getSortAsc() ? Sort.Direction.DESC : Sort.Direction.ASC, query.getSortKey());
        Page<Task> page = taskDao.findAll(new Specification<Task>() {
            @Override
            public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<Predicate>();
                if (!Strings.isNullOrEmpty(query.getLessonName())) {
                    Long[] lessonIds = lessonDao.findIdsByName(query.getLessonName());
                    if (lessonIds.length <= 0) {
                        lessonIds = new Long[]{-1l};
                    }
                    list.add(root.get("lessonId").in(lessonIds));
                }
                if (!Strings.isNullOrEmpty(query.getTeacherName())) {
                    Long[] teacherIds = teacherDao.findIdsByName(query.getTeacherName());
                    if (teacherIds.length <= 0) {
                        teacherIds = new Long[]{-1l};
                    }
                    list.add(root.get("teacherId").in(teacherIds));
                }
                if (!Strings.isNullOrEmpty(query.getCommunityName())) {
                    Long[] communityIds = communityDao.findIdsByName(query.getCommunityName());
                    if (communityIds.length <= 0) {
                        communityIds = new Long[]{-1l};
                    }
                    list.add(root.get("communityId").in(communityIds));
                }
                if (query.getStartTime() > 0 && query.getEndTime() > 0) {
                    list.add(criteriaBuilder.le(root.get("startTime").as(Long.class), query.getEndTime()));
                    list.add(criteriaBuilder.gt(root.get("endTime").as(Long.class), query.getStartTime()));
                }
                criteriaQuery.where(list.toArray(new Predicate[0]));
                return criteriaQuery.getRestriction();
            }
        }, pageable);
        fillTaskList(page.getContent());
        return page;
    }

    public List<Task> findByCondition(long startTime, long endTime, int status) {
        List<Task> tasks = null;
        if (status == all.getStatus()) {
            tasks = taskDao.findAll(startTime, endTime);
        } else if (status == paired.getStatus()) {
            tasks = taskDao.findByTeacherIdNotNull(startTime, endTime);
        } else if (status == unpaired.getStatus()) {
            tasks = taskDao.findByTeacherIdIsNull(startTime, endTime);
        }
        fillTaskList(tasks);
        return tasks;
    }

    public List<Task> findValid() {
        long now = System.currentTimeMillis();
        List<Task> tasks = taskDao.findValidTask(now);
        fillTaskList(tasks);
        return tasks;
    }

    public List<Task> findValidByTeacher(String code) {
        long now = System.currentTimeMillis();
        Teacher teacher = teacherDao.findByCode(code);
        if (teacher == null) {
            return new ArrayList<>();
        }
        List<TeacherLesson> tls = teacherLessonDao.findTeacherLessonsByTeacherIds(Lists.newArrayList(teacher.getId()));
        if (tls == null || tls.size() <= 0) {
            return new ArrayList<>();
        }
        List<Long> lessonIds = new ArrayList<>();
        for (TeacherLesson tl : tls) {
            lessonIds.add(tl.getLessonId());
        }
        List<Task> tasks = taskDao.findValidTaskByLessonIds(now, lessonIds);
        fillTaskList(tasks);
        return tasks;
    }

    private void fillTaskList(List<Task> tasks) {
        if (tasks == null || tasks.size() <= 0) {
            return;
        }
        fillTasks(tasks.toArray(new Task[0]));
    }

    private void fillTasks(Task... tasks) {
        if (tasks == null) {
            return;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Long> teacherIds = new ArrayList<>();
        List<Long> lessonIds = new ArrayList<>();
        List<Long> communityIds = new ArrayList<>();
        for (Task task : tasks) {
            if (task == null) {
                continue;
            }
            teacherIds.add(task.getTeacherId());
            lessonIds.add(task.getLessonId());
            communityIds.add(task.getCommunityId());
        }
        List<Lesson> lessons = lessonDao.findLessonsByIds(lessonIds);
        List<Teacher> teachers = teacherDao.findTeachersByIds(teacherIds);
        List<Community> communities = communityDao.findCommunitiesByIds(communityIds);
        Map<Long, Lesson> lessonMap = new HashMap<>();
        Map<Long, Teacher> teacherMap = new HashMap<>();
        Map<Long, Community> communityMap = new HashMap<>();
        if (lessons != null) {
            for (Lesson lesson : lessons) {
                lessonMap.put(lesson.getId(), lesson);
            }
        }
        if (teachers != null) {
            for (Teacher teacher : teachers) {
                teacherMap.put(teacher.getId(), teacher);
            }
        }
        if (communities != null) {
            for (Community community : communities) {
                communityMap.put(community.getId(), community);
            }
        }
        for (Task task : tasks) {
            if (task == null) {
                continue;
            }
            long teacherId = task.getTeacherId();
            long lessonId = task.getLessonId();
            long communityId = task.getCommunityId();
            task.setLesson(lessonMap.get(lessonId));
            task.setTeacher(teacherMap.get(teacherId));
            task.setCommunity(communityMap.get(communityId));
            task.setStartDate(sdf.format(new Date(task.getStartTime())));
            task.setEndDate(sdf.format(new Date(task.getEndTime())));
        }
    }

    public Task findOne(long id) {
        Task task = taskDao.findOne(id);
        fillTasks(task);
        return task;
    }

    public Task add(Task task) {
        if (task == null || task.getId() > 0) {
            return null;
        }
        task.setCreateTime(System.currentTimeMillis());
        Task newTask = taskDao.save(task);
        fillTasks(newTask);
        return newTask;
    }

    public Task update(Task task) {
        if (task == null || task.getId() <= 0) {
            return null;
        }
        Task newTask = taskDao.save(task);
        fillTasks(newTask);
        return newTask;
    }

    public boolean selectTask(long teacherId, long taskId) {
        long now = System.currentTimeMillis();
        taskDao.updateTeacherIdAndTime(teacherId, now, taskId);
        return true;
    }

    public boolean delete(long id) {
        taskDao.delete(id);
        return true;
    }
}
